/**
 * \file  antiviral.h
 * \brief Definition of Antiviral class.
 *
 * LAV: Lib Anti Virals
 * <http://lav.googlecode.com/>
 * Copyright (C) 2010 Velez Ezequiel, Peralta Andres, FuDePAN
 *
 * This file is part of the LAV project.
 *
 * Contents:       Header file for LAV providing class Antiviral.
 *
 * System:         LAV
 * Language:       C++
 *
 * Author:         Velez Ezequiel
 * E-Mail:         e.s.velez@gmail.com
 *
 * Author:         Peralta Andres
 * E-Mail:         andres.vhd@gmail.com
 *
 * Author:         Boretto Martin
 * E-Mail:         martinboretto@gmail.com
 *
 * Author:         Lenarduzzi Federico
 * E-Mail:         federicolenarduzzi@gmail.com
 *
 * LAV is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LAV is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LAV.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef ANTIVIRAL_H
#define ANTIVIRAL_H

#define NO_BITWISE_ENUMS
#include <mili/mili.h>
#include "lav/sequence.h"
#include "lav/possible_mutants.h"

namespace lav
{

/** This typedef defines a triplet set to resistances applicance */
typedef std::set<biopp::Triplet> TripletSet;

/** This typedef defines a triplets list */
typedef std::list<biopp::Triplet> TripletList;


/** This typedef defines the value of distances between mutants */
typedef float DistanceValue;


/** This typedef defines a pair with the triplet's list and the minimal distance */
typedef std::pair<TripletSet, DistanceValue> TripletVal;


/** This typedef defines a set of attributes belongs to an antiviral */
typedef mili::VariantsSet AttribSet;


/** This typedef defines a set of names of antiviral */
typedef std::string AntiviralsNames;


/** This typedef defines the class of antiviral */
typedef std::string AntiviralClass;


/** This typedef defines an identifier for an antiviral */
typedef uint AntiviralIdentifier;


/** This typedef defines a list of identifiers of antiviral */
typedef std::list<AntiviralIdentifier> AntiviralIdentifierContainer;


/**
 * This struct defines a pair with the relationship mutants minimal distance
 */
struct MutantDist
{

    /**
     * Copy constructor
     */
    MutantDist(const SequenceSet& sequences, DistanceValue distance)
        : sequences(sequences), distance(distance)
    {}


    /**
     * This function updates the distance value
     * @param new_distance new value of distance to update
     */
    void set_distance(const DistanceValue& new_distance)
    {
        distance = new_distance;
    }


    /**
     * This function adds a pseudosequence into the list of ones
     * @param new_sequence sequence to will be inserted
     */
    void add_mutant(biopp::PseudoNucSequence new_sequence)
    {
        mili::insert_into(sequences, new_sequence);
    }


private:

    SequenceSet sequences;
    DistanceValue distance;

};




/**
 * This class defines the Antiviral's interface
 */
class Antiviral
{

    AttribSet _attributes; // Antiviral attributes

public:

    /**
     * Copy constructor
     */
    Antiviral(const AntiviralsNames& name)
    {
        _attributes.insert("name", name);
    }


    /**
     * Copy constructor
     */
    Antiviral(const Antiviral& other)
    {
        _attributes = other._attributes;
    }


    /**
     * This template defines the attribute set
     */
    template<class T>
    void set_attrib(const AntiviralsNames& name, const T& initValue)
    {
        _attributes.insert(name, initValue);
    }


    /**
     * This template defines a method which return an attribute according to
     * his name
     */
    template<class T>
    void get_attrib(const AntiviralsNames& name, T& value) const throw(SystemError)
    {
        try
        {
            _attributes.get_element(name, value);
        }
        catch (const mili::BadElementType& exc)
        {
            throw SystemError("at Antiviral : Bad Attribute Type");
        }
        catch (const mili::BadElementName& exc)
        {
            throw SystemError("at Antiviral : Bad Attribute Name");
        }
    }


    /**
     * This method prints all attributes from an antiviral (this)
     */
    inline void print_attributes() const
    {
        mili::CAutonomousIterator<AttribSet> it(_attributes);
        while (!it.end())
        {
            std::cout << it->first << ": " << it->second << "." << std::endl;
            ++it;
        }
    }

    /**
    * This method checks the antiviral's applicanse with de sequence
    * @param sequence Represents the patient's virus
    * @return Distance between the current antiviral and sequence
    */
    virtual biopp::NucDistance applies(const biopp::PseudoNucSequence& sequence) const = 0;


    /**
    * This method applies an antiviral (this) to the sequence and generate mutants
    * @param sequence Represents the patient's virus
    * @param mutations It will contain the mutants generated
    */
    virtual void mutate_sequence(const biopp::PseudoNucSequence& sequence, MutantDist& mutations) const = 0;


    /**
     * Antiviral's destructor
     */
    virtual ~Antiviral()
    {}

};

}

#endif
